#include <mitkGL.h>

#include "WxPointedSticksMapper2D.h"
#include "mitkBaseRenderer.h"
#include "mitkGeometry2D.h"
#include "mitkPlaneGeometry.h"
#include "mitkSurface.h"

#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkDataArray.h>


mitk::WxPointedSticksMapper2D::WxPointedSticksMapper2D()
{

}

mitk::WxPointedSticksMapper2D::~WxPointedSticksMapper2D()
{

}

const mitk::Surface *mitk::WxPointedSticksMapper2D::GetInput(void)
{
  if(m_Surface.IsNotNull())
    return m_Surface;

  return static_cast<const Surface * > ( GetData() );
}

void mitk::WxPointedSticksMapper2D::SetDataNode( mitk::DataNode::Pointer node )
{
  Superclass::SetDataNode( node );

  bool useCellData;
  if (dynamic_cast<BoolProperty *>(node->GetProperty("deprecated useCellDataForColouring")) == NULL)
    useCellData = false;
  else
    useCellData = dynamic_cast<BoolProperty *>(node->GetProperty("deprecated useCellDataForColouring"))->GetValue();

  if (!useCellData)
  {
    // search min/max point scalars over all time steps
    vtkFloatingPointType dataRange[2] = {0,0};
    vtkFloatingPointType range[2];

    Surface::Pointer input  = const_cast< Surface* >(dynamic_cast<const Surface*>( this->GetDataNode()->GetData() ));
    if(input.IsNull()) return;
    const TimeSlicedGeometry::Pointer inputTimeGeometry = input->GetTimeSlicedGeometry();
    if(( inputTimeGeometry.IsNull() ) || ( inputTimeGeometry->GetTimeSteps() == 0 ) ) return;
    for (unsigned int timestep=0; timestep<inputTimeGeometry->GetTimeSteps(); timestep++)
    {
      vtkPolyData * vtkpolydata = input->GetVtkPolyData( timestep );
      if((vtkpolydata==NULL) || (vtkpolydata->GetNumberOfPoints() < 1 )) continue;
      vtkDataArray *vpointscalars = vtkpolydata->GetPointData()->GetScalars();
      if (vpointscalars) {
        vpointscalars->GetRange( range, 0 );
        if (dataRange[0]==0 && dataRange[1]==0) {
          dataRange[0] = range[0];
          dataRange[1] = range[1];
        }
        else {
          if (range[0] < dataRange[0]) dataRange[0] = range[0];
          if (range[1] > dataRange[1]) dataRange[1] = range[1];
        }
      }
    }
  }
}


void mitk::WxPointedSticksMapper2D::Paint(mitk::BaseRenderer * renderer)
{
  if(IsVisible(renderer)==false) return;

  Surface::Pointer input  = const_cast<Surface*>(this->GetInput());

  if(input.IsNull())
    return;

  //
  // get the TimeSlicedGeometry of the input object
  //
  const TimeSlicedGeometry* inputTimeGeometry = input->GetTimeSlicedGeometry();
  if(( inputTimeGeometry == NULL ) || ( inputTimeGeometry->GetTimeSteps() == 0 ) )
    return;


  //
  // get the world time
  //
  mitk::Geometry2D::ConstPointer worldGeometry = renderer->GetCurrentWorldGeometry2D();
  assert( worldGeometry.IsNotNull() );

  ScalarType time = worldGeometry->GetTimeBounds()[ 0 ];
  int timestep=0;

  if( time > ScalarTypeNumericTraits::NonpositiveMin() )
    timestep = inputTimeGeometry->MSToTimeStep( time );

 // int timestep = this->GetTimestep();

  if( inputTimeGeometry->IsValidTime( timestep ) == false )
    return;

  mitk::Vector3D needleDirection=input->GetUpdatedGeometry()->GetAxisVector(0);
  mitk::Vector3D needleWide=input->GetGeometry()->GetAxisVector(1);
  mitk::Point3D needleOrigin=input->GetGeometry()->GetOrigin();
  mitk::Point3D needleEnd=needleOrigin+needleDirection;
  mitk::Point2D needleOrigin2d,needleEnd2d;

  PlaneGeometry::ConstPointer worldPlaneGeometry = dynamic_cast<const PlaneGeometry*>(worldGeometry.GetPointer());
  worldGeometry->Map(needleEnd,needleEnd2d);
  worldGeometry->Map(needleOrigin,needleOrigin2d);
  DisplayGeometry* displayGeometry=renderer->GetDisplayGeometry();
  displayGeometry->WorldToDisplay(needleOrigin2d, needleOrigin2d);
  displayGeometry->WorldToDisplay(needleEnd2d, needleEnd2d);

  mitk::Vector2D needleDirection2d=needleEnd2d-needleOrigin2d;
  float needlleLength=needleDirection2d.GetNorm();
  needleDirection2d.Normalize();
  mitk::Vector2D needleWideDir2d;
  needleWideDir2d[0]=-needleDirection2d[1];
  needleWideDir2d[1]=needleDirection2d[0];
  needleWideDir2d.Normalize();
  float f=needleWide.GetNorm()*0.5;
  if(f>3.0)f=3.0;
  needleWideDir2d=needleWideDir2d*f;
  mitk::Point2D handle2d= needleOrigin2d+needleDirection2d*needlleLength*0.1;
  mitk::Point2D e2d1=needleEnd2d+needleWideDir2d,e2d2=needleEnd2d-needleWideDir2d;
  mitk::Point2D o2d1=handle2d+needleWideDir2d,o2d2=handle2d-needleWideDir2d;

  //apply color and opacity read from the PropertyList
  ApplyProperties(renderer);

  float rgba[4]={1.0f,1.0f,1.0f,1.0f};
  // check for color prop and use it for rendering if it exists
  GetColor(rgba, renderer);
  // check for opacity prop and use it for rendering if it exists
  GetOpacity(rgba[3], renderer);

  glShadeModel(GL_SMOOTH);

  glBegin (GL_POLYGON);
  glColor4f(rgba[0]*0.5,rgba[1]*0.5,rgba[2]*0.5,rgba[3]);
  glVertex2f(e2d2[0], e2d2[1]);
  glVertex2f(o2d2[0], o2d2[1]);
  glColor4fv(rgba);
  glVertex2f(handle2d[0], handle2d[1]);
  glVertex2f(needleEnd2d[0], needleEnd2d[1]);
  glEnd();

  glBegin (GL_POLYGON);
  glColor4f(rgba[0]*0.5,rgba[1]*0.5,rgba[2]*0.5,rgba[3]);
  glVertex2f(e2d1[0], e2d1[1]);
  glVertex2f(o2d1[0], o2d1[1]);
  glColor4fv(rgba);
  glVertex2f(handle2d[0], handle2d[1]);
  glVertex2f(needleEnd2d[0], needleEnd2d[1]);
  glEnd();

  glBegin (GL_LINE_LOOP);
  glColor4f(0,0,0,1);
  glVertex2f(e2d1[0], e2d1[1]);
  glVertex2f(e2d2[0], e2d2[1]);
  glVertex2f(o2d2[0], o2d2[1]);
  glVertex2f(o2d1[0], o2d1[1]);
  glEnd();


  glBegin (GL_POLYGON);
  glColor4f(rgba[0]*0.75,rgba[1]*0.75,rgba[2]*0.75,rgba[3]);
  glVertex2f(o2d2[0], o2d2[1]);
  glVertex2f(o2d1[0], o2d1[1]);
  glColor4fv(rgba);
  glVertex2f(needleOrigin2d[0], needleOrigin2d[1]);
  glEnd();

  glBegin (GL_LINE_LOOP);
  glColor4f(0,0,0,1);
  glVertex2f(needleOrigin2d[0], needleOrigin2d[1]);
  glVertex2f(o2d2[0], o2d2[1]);
  glVertex2f(o2d1[0], o2d1[1]);
  glEnd();
  glColor4fv(rgba);


}

void mitk::WxPointedSticksMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite)
{
  node->AddProperty( "layer", mitk::IntProperty::New(100), renderer, overwrite);
  Superclass::SetDefaultProperties(node, renderer, overwrite);
}

void mitk::WxPointedSticksMapper2D::ApplyProperties(mitk::BaseRenderer* renderer)
{
  Superclass::ApplyProperties(renderer);

}
